
#ifndef RING_BUFFER_DEF_HPP
#define RING_BUFFER_DEF_HPP

/**
 * @brief RingBuffer 简单实现
 * 核心目标 ：不够时自动扩展大小，以及空余过大时收缩大小
 */

#include <allocator.hpp>
#include <exceptdef.h>

#define RING_BUFFER_MIN_SIZE 128 // 最小数据域

template <typename T, size_t N = RING_BUFFER_MIN_SIZE, typename Alloc = TingSTL::allocator<T>>
class RingBuffer {
public:
    static constexpr size_t chunkSize = N;
    using allocator = typename Alloc;

private:
    size_t _cap;
    size_t _read;  // 读指针
    size_t _write; // 写指针
    T *_buf;       // buf
public:
    RingBuffer(const RingBuffer &) = default; // 禁止拷贝
    RingBuffer &operator=(const RingBuffer &) = delete;

    RingBuffer() {
        _buf = allocator::allocate(N);
        _cap = N;
        _read = _write = 0;
    }

    ~RingBuffer() {
        allocator::destroy(_buf + _write, _buf + _read);
        allocator::deallocate(_buf);
        _buf = nullptr;
    }

    // ////////////////////////////////// 空间容量相关 //////////////////////////////

    // 已经使用了多少空间
    inline size_t size() const noexcept {
        return (_write - _read + _cap) % _cap;
    }

    inline size_t capacity() const noexcept {
        return _cap;
    }

    inline bool empty() const noexcept {
        return _write == _read;
    }

    // 调整容量
    void reserve(size_t newCap) {
        TING_DEBUG("RingBuffer reserve, newCap : %zd", newCap);

        if (newCap == _cap) return;
        T *newBuf = allocator::allocate(newCap);

        //  allocate and copy
        auto i = _read;
        try {
            for (; i < _write; ++i) {
                allocator::construct(newBuf + i, std::move(_buf[i]));
            }
        } catch (...) {
            allocator::destroy(newBuf + _read, newBuf + i);
            allocator::deallocate(newBuf);
            throw;
        }
        allocator::destroy(_buf + _read, _buf + _write);
        allocator::deallocate(_buf);
        _buf = newBuf;
        _cap = newCap;
    }

    // /////////////////////////// 读写相关 ////////////////////////
    // 写入一个元素
    template <typename... Args>
    void write(Args... args) {
        if (size() + 1 >= _cap) {
            auto newCap = _cap + ((_cap + 1) >> 1); // 1.5 倍 扩容
            reserve(newCap);
        }
        allocator::construct(_buf + _write, std::forward<Args>(args)...);
        _write = (_write + 1) % _cap;
    }

    // 读取一个元素
    T read() {
        TING_ASSERT(!empty(), "ring buffer is empty,cant read");
        T ret(std::move(*(_buf + _read)));
        allocator::destroy(_buf + _read);
        _read = (_read + 1) % _cap;
        return ret;
    }
};

#endif // RING_BUFFER_DEF_HPP